fix(composer): restore focus after dialog close#16733
Conversation
kangfenmao
left a comment
There was a problem hiding this comment.
LGTM — verified no double focus restoration on edit-save (onOpenChange fires before onSaved; handleEditSaved intentionally does not re-restore) and single restore on create-submit/cancel paths. Visible WebSearch button safely captures event.currentTarget before the async close. Types and renderBelowControls wiring check out; CI green. Two optional test-convention nits (prefer the @test-mocks/requestAnimationFrame alias over the deep relative path; move the mid-file import to the top in the three tool test files) — non-blocking.
cbac630 to
0932be5
Compare
eeee0717
left a comment
There was a problem hiding this comment.
Findings:
- Important:
src/renderer/components/composer/tools/components/WebSearchButton.tsx:97restores focus fromafterCloseeven when the user confirms the missing-provider dialog andonOknavigates to/settings/websearch.AppModalawaitsonOk, closes the modal, then runsafterClosefrom the delayed removal path, so the composer/editor can already be stale or unmounted by the timeinputAdapter.focus()runs. Please restrict the restore to dismiss/cancel/overlay close, or guard that the target is still mounted/current before focusing it.
Open questions:
- None.
Summary:
The broader focus-restoration wiring looks sound, and I did not repeat the existing non-blocking import-convention/test-style notes. This is a comment review rather than a request for changes because the issue is limited to the missing-provider navigation branch.
Verification:
- Reviewed PR #16733 at head
0932be501d9613840c548afee21ef4e53ea9d74fin/Users/cherryai004/Documents/Cherry_Studio_Dev/cherry-studio-pr-review/.codex-tmp/pr-review-sweep-20260706T0830Z/pr-16733-0932be5with three reviewer slices plus coordinator pass. - Checked GitHub CI via
gh; static/core checks passed, and final long-running jobs were refreshed before submission. - Ran
git diff --check origin/main...HEAD. - Did not run local
pnpm lint/test/format, per repository review rules.
修复后请 request eeee0717 再进行后续 review。
AtomsH4
left a comment
There was a problem hiding this comment.
LGTM
范围:为 composer 的对话框、选择器、快捷短语、附件 picker、web search confirm 等交互补上输入框 focus restore,并增加 requestAnimationFrame 测试 mock 和相关 UI 回归测试。
影响:用户从这些浮层/菜单退出后可以回到 composer 继续输入,减少键盘流中断;restore 只在相关关闭/确认路径触发,未看到重复聚焦或误抢焦点问题。未发现 blocker/warning。
@eeee0717 I've addressed your review and pushed to the PR branch: Fix: When web search provider is missing, the confirmed redirect to Additional verification:
I've added regression tests to cover the scenario where focus is not restored after confirmed redirect. Please help review again. Original Content@eeee0717 已按你的 review 处理并推到 PR 分支: 修复点:缺少 web search provider 时,确认跳转 补充验证:
已补回归测试覆盖确认跳转后不恢复焦点的场景,麻烦再帮忙 review。 |
AtomsH4
left a comment
There was a problem hiding this comment.
改动范围:本次新增了 composer Web Search 按钮/plus menu 弹窗关闭后的焦点恢复逻辑,并补充了缺少搜索 provider 时跳转设置页不应恢复触发按钮焦点的测试。
影响:交互方向是合理的,可以避免从确认弹窗进入设置页时焦点被拉回旧按钮;但最新提交在测试文件里重复导入 installSyncRafMock,导致 basic-checks 的 oxlint 失败。该 CI blocker 修掉后我再复核。
eeee0717
left a comment
There was a problem hiding this comment.
Findings:
- None.
Open questions:
- None.
Summary:
The previously reported missing-provider navigation focus issue is fixed at head c039728. The follow-up duplicate RAF mock import was removed, and I did not find additional blocking issues in the composer/tool/selector focus restoration changes.
Verification:
- Reviewed PR #16733 at head c039728 in /Users/cherryai004/Documents/Cherry_Studio_Dev/cherry-studio-pr-review/.codex-tmp/pr-review-sweep-20260706T0906Z/pr-16733-c039728 with three reviewer slices plus coordinator pass.
- Checked GitHub CI via gh: changes, catalog-hand-edit-check, changeset-check, basic-checks, general-test, and render-test passed; notify/translate/claude skipped.
- Ran git diff --check origin/main...HEAD.
- Did not run local pnpm lint/test/format, per repository review rules.
AtomsH4
left a comment
There was a problem hiding this comment.
LGTM
范围:为 composer 的对话框、选择器、快捷短语、附件 picker、web search confirm 等交互补上输入框 focus restore;最新提交还修复了 WebSearchButton 测试里重复导入 installSyncRafMock 的 lint blocker。
影响:用户从这些浮层/菜单退出后可以回到 composer 继续输入;确认跳转到 Web Search 设置页时不会再把焦点拉回旧按钮。当前 head c039728 的 basic-checks、general-test、render-test 均已通过,未发现新的 blocker/warning。
- Settings window removal (#16489): drop SettingsApp's host mount; the settings page now renders inside the main window, already host-covered. - Composer focus-restore (#16733): reimplement over the popup track — add ConfirmPopupProps.focusOnClose (Radix onCloseAutoFocus + preventDefault) and route WebSearchButton through it, replacing the afterClose + requestAnimationFrame focus race. - Re-apply the window.toast/window.modal -> toast/popup codemod onto upstream's moved/renamed files (Appearance/Dependencies/System settings, MCP, paintings, knowledge) and SystemSettings' new call sites.
What this PR does
Before this PR:
Closing composer-adjacent dialogs and native pickers could leave focus on the dialog trigger, the page body, or another intermediate control instead of returning to the composer input. The save path for assistant/agent edit dialogs could also schedule duplicate focus restoration callbacks.
After this PR:
Composer tool actions and assistant/agent resource dialogs restore focus consistently after closing. Save callbacks refresh data without scheduling a second focus restoration, and tests cover cancel/save paths plus tool-menu and visible-button web search flows.
Fixes # N/A
Why we need it and why it was done in this way
The following tradeoffs were made:
Focus restoration is explicitly wired through the composer input adapter and deferred with
requestAnimationFrameso it runs after dialogs and overlays close. For the visible Web Search button, the fallback focus target is the clicked trigger because that path does not have a composer input adapter.The following alternatives were considered:
Relying on Radix/native default focus behavior was rejected because these flows are opened from several indirect entry points and the restored target was inconsistent. Using duplicated
requestAnimationFramestubs in each test was also rejected in favor of a shared test helper.Links to places where the discussion took place: N/A
Breaking changes
If this PR introduces breaking changes, please describe the changes and the impact on users.
None.
Special notes for your reviewer
The file picker cancel path intentionally restores focus to the composer as part of the same "close the transient UI and continue typing" behavior.
Checklist
This checklist is not enforcing, but it's a reminder of items that could be relevant to every PR.
Approvers are expected to review this list.
mainfor active development,v1for v1 maintenance fixes/gh-pr-review,gh pr diff, or GitHub UI) before requesting review from othersRelease note